import { getEnvConfig } from '../config/index'
import dayjs from 'dayjs'

const timeStringFormat = 'YYYY-MM-DD HH:mm:ss'

// 存数据时，若未提供过期时间，则提供默认值
function _getDefaultExpiredTime () {
  const { defaultCacheStoreTime } = getEnvConfig()
  return dayjs().add(defaultCacheStoreTime, 'second').format(timeStringFormat)
}

/**
 * 设置缓存
 * @param {String} key
 * @param {Any} data 要存储的数据
 * @param {String} expiredTime 过期时间，格式为YYYY-MM-DD HH:mm:ss，例：2100-01-01 00:00:00
 * */ 
function setCache (key, data, expiredTime = null) {
  const expTime = expiredTime ? expiredTime : _getDefaultExpiredTime()
  wx.setStorageSync(key, { data, expiredTime: expTime })
}

// 获取缓存数据
function _getCacheData (key) {
  return wx.getStorageSync(key)
}

// 清除缓存数据
function removeCache (key) {
  wx.removeStorageSync(key)
}

// 清空缓存数据
function clearCache () {
  wx.clearStorageSync()
}

// 检查数据是否过期
function _checkDataValid (data) {
  if (data && data.expiredTime) {
    return dayjs(data.expiredTime).valueOf() - dayjs().valueOf() > 0
  } else {
    return false
  }
}

// 检查数据的有效性
function _checkData (key, data) {
  const msgFormatError = '格式不正确的缓存数据，请检查传入的key值是否正确'
  if (typeof data !== 'object') {
    throw new Error(msgFormatError)
  }
  if (!data) {
    return null
  }
  const keys = Object.keys(data)
  if (keys.includes('data') && keys.includes('expiredTime')) {
    if (_checkDataValid(data)) {
      return data.data
    } else {
      removeCache(key)
      return null
    }
  } else {
    throw new Error(msgFormatError)
  }
}

// 根据传入的方法获取数据，并设置缓存
async function _setCacheByFn (key, expiredTime, fn) {
  if (fn) {
    const data = await fn()
    setCache(key, data, expiredTime)
    return data
  } else {
    return null
  }
}

/**
 * 获取缓存
 * @param {String} key
 * @param {Object} options
 * @param {Function} options.getDataFn 数据获取方法，不必须，若存在，当数据不存在或过期时会调用此方法获取数据
 * @param {String} options.expiredTime 过期时间，renewalFn存在时有效，格式为YYYY-MM-DD HH:mm:ss，例：2100-01-01 00:00:00
*/
async function getCache (key, options = {}) {
  const res = _getCacheData(key)
  if (res) {
    const data = _checkData(key, res)
    if (data) {
      return data
    } else {
      return await _setCacheByFn(key, options.expiredTime, options.getDataFn)
    }
  } else {
    return await _setCacheByFn(key, options.expiredTime, options.getDataFn)
  }
}

export {
  setCache,
  getCache,
  removeCache,
  clearCache
}
